﻿#region Using Statements
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.IO;
using System.Windows;
using System.Windows.Resources;
#endregion

namespace WpfFootball.Parser
{
    /// <summary>
    /// The IOmanager contains routines that allows the application to use a variety of
    /// I/O operations such as downloading the content of a web page and opening local 
    /// files.
    /// </summary>
    public class IOManager
    {
        #region Fields
        private string TEAM_DB_PATH = @"/Resources/TeamDB/teams.txt";
        private string MANAGED_TEAMS_PATH = @"/Resources/TeamDB/managedTeams.txt";
        private string SETTINGS_PATH = @"/Resources/Settings/";

        private static IOManager instance;
        #endregion

        private IOManager()
        {  }

        /// <summary>
        /// Gets the instance of this object.
        /// </summary>
        public static IOManager Instance()
        {
            if (instance == null)
            {
                instance = new IOManager();
                return instance;
            }
            else
            {
                return instance;
            }
        }

        /// <summary>
        /// Attempts to download the content of a webpage.
        /// </summary>
        /// <param name="url">The url of the page to load.</param>
        /// <returns>The content of the page, in html format.</returns>
        public string LoadWebPage(string url)
        {
            try
            {
                WebClient client = new WebClient();
                return client.DownloadString(url);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Failed to load page. " + url + ". Reason: " + ex.Message);
                return string.Empty;
            }
        }
        
        /// <summary>
        /// Builds a ViewSettings object by parsing the stored settings in the specified
        /// source.
        /// </summary>
        /// <param name="sorceUrl">The url to the source that contains the settings to be parsed</param>
        /// <returns>A ViewSettings object with the parsed settings from the specified source.</returns>
        private ViewSettings ParseViewSettingsFromSource(string sourceUrl)
        {
            ViewSettings viewSettings = new ViewSettings();
            
            string[] rawSettings = GetLinesFromFile(sourceUrl)[0].Split('|');
            string[] viewLocationSettings = rawSettings[3].Split(',');

            Point locationPoint = new Point();
            locationPoint.X = int.Parse(viewLocationSettings[0]);
            locationPoint.Y = int.Parse(viewLocationSettings[1]);

            viewSettings.AutoUpdate = bool.Parse(rawSettings[0]);
            viewSettings.UpdateFrequency = int.Parse(rawSettings[1]);
            viewSettings.EntryCounter = int.Parse(rawSettings[2]);
            viewSettings.Location = locationPoint;

            return viewSettings;
        }

        /// <summary>
        /// Retrieves the settings of a specified view.
        /// </summary>
        /// <param name="viewName">The name of the view to get the settings.</param>
        /// <returns>A ViewSettings that contains the settings of the specified view.</returns>
        public ViewSettings GetViewSettings(string teamName, ViewKind viewKind)
        {
            switch (viewKind)
            {
                case ViewKind.FORUM:
                    return ParseViewSettingsFromSource(SETTINGS_PATH + "\\" + teamName + "ForumViewSettings.txt");
                case ViewKind.NEWS:
                    return ParseViewSettingsFromSource(SETTINGS_PATH + "\\" + teamName + "NewsViewSettings.txt");
                case ViewKind.FIXTURES:
                    return ParseViewSettingsFromSource(SETTINGS_PATH + "\\" + teamName + "FixturesViewSettings.txt");
                default:
                    return ViewSettings.GetDefault(viewKind);
            }
        }

        /// <summary>
        /// Overwrites the settings file of a specified view.
        /// </summary>
        /// <param name="viewSettings">The object that contains the settings to be written.</param>
        public void WriteViewSettings(string teamName, ViewKind viewKind, ViewSettings viewSettings)
        {
            string settingsLine = viewSettings.AutoUpdate.ToString() + "|" + viewSettings.UpdateFrequency + "|" + viewSettings.EntryCounter + "|" + (viewSettings.Location.X) + "," + (viewSettings.Location.Y);

            switch (viewKind)
            {
                case ViewKind.FORUM:
                    WriteLineToFile(SETTINGS_PATH + "\\" + teamName + "ForumViewSettings.txt", settingsLine);
                    break;
                case ViewKind.NEWS:
                    WriteLineToFile(SETTINGS_PATH + "\\" + teamName + "NewsViewSettings.txt", settingsLine);
                    break;
                case ViewKind.FIXTURES:
                    WriteLineToFile(SETTINGS_PATH + "\\" + teamName + "FixturesViewSettings.txt", settingsLine);
                    break;
            }
        }

        /// <summary>
        /// Deletes all view settings attached to a team.
        /// </summary>
        /// <param name="teamName">The name of the team to delete the views settings.</param>
        public void DeleteViewsSettings(string teamName)
        {
            File.Delete(SETTINGS_PATH + "\\" + teamName + "ForumViewSettings.txt");
            File.Delete(SETTINGS_PATH + "\\" + teamName + "NewsViewSettings.txt");
            File.Delete(SETTINGS_PATH + "\\" + teamName + "FixturesViewSettings.txt");
        }

        /// <summary>
        /// Reads the names of all teams from the application database.
        /// </summary>
        /// <returns>An array containing the name of each team.</returns>
        public string[] GetAvailableTeamNames()
        {
            try
            {
                List<string> teamNames = new List<string>();
                StreamReader fileReader = new StreamReader(TEAM_DB_PATH);
                string currentTeam = string.Empty;

                while ((currentTeam = fileReader.ReadLine()) != null)
                {
                    teamNames.Add(currentTeam.Split('|')[0]);
                }
                fileReader.Close();

                return teamNames.ToArray();
            }
            catch (FileNotFoundException fnfex)
            {
                Console.WriteLine(fnfex.Message);
                return null;
            }
        }

        /// <summary>
        /// Attempts to find the news source of a given team from
        /// the team database.
        /// </summary>
        /// <param name="teamName">The name of the team to find the news source of.</param>
        /// <returns>An url representing the source of the news for the team.</returns>
        public string GetTeamNewsSource(string teamName)
        {
            StreamReader fileReader = new StreamReader(TEAM_DB_PATH);
            string currentTeamSettings = string.Empty;
            string teamSource = string.Empty;

            while ((currentTeamSettings = fileReader.ReadLine()) != null)
            {
                string[] teamData = currentTeamSettings.Split('|');

                if (teamData[0].Equals(teamName))
                {
                    teamSource = teamData[1];
                    break;
                }
            }
            fileReader.Close();

            return teamSource;
        }

        /// <summary>
        /// Retrieves the forum team url from the teams database.
        /// </summary>
        /// <param name="teamName">The name of the team.</param>
        /// <returns>A string containing the forum url.</returns>
        public string GetTeamForumSource(string teamName)
        {
            StreamReader fileReader = new StreamReader(TEAM_DB_PATH);
            string currentTeam = string.Empty;
            string teamSource = string.Empty;

            while ((currentTeam = fileReader.ReadLine()) != null)
            {
                string[] teamData = currentTeam.Split('|');

                if (teamData[0].Equals(teamName))
                {
                    teamSource = teamData[2];
                    break;
                }
            }
            fileReader.Close();

            return teamSource;
        }

        /// <summary>
        /// Retrieves the url to the icon file of a team.
        /// </summary>
        /// <param name="teamName">The name of the team.</param>
        /// <returns>An url containg the path to the icon.</returns>
        public string GetTeamIconSource(string teamName)
        {
            StreamReader fileReader = new StreamReader(TEAM_DB_PATH);
            string currentTeam = string.Empty;
            string iconSource = string.Empty;

            while ((currentTeam = fileReader.ReadLine()) != null)
            {
                string[] teamData = currentTeam.Split('|');

                if (teamData[0].Equals(teamName))
                {
                    iconSource = teamData[3];
                    break;
                }
            }
            fileReader.Close();

            return iconSource;
        }

        /// <summary>
        /// Checks if a managed team already exists.
        /// </summary>
        /// <param name="teamName">The name of the team to check.</param>
        /// <returns>True if the team is managed, false otherwise.</returns>
        public bool ManagedTeamExists(string teamName)
        {
            StreamReader fileReader = new StreamReader(MANAGED_TEAMS_PATH);
            string currentTeam = string.Empty;

            while ((currentTeam = fileReader.ReadLine()) != null)
            {
                if (currentTeam.Equals(teamName))
                {
                    fileReader.Close();
                    return true;
                }
            }

            fileReader.Close();
            return false;
        }

        /// <summary>
        /// Register a new team to the list of managed teams.
        /// </summary>
        /// <param name="teamName">The name of the team to manage.</param>
        public void AddTeamToManage(string teamName)
        {
            StreamWriter fileWriter = new StreamWriter(MANAGED_TEAMS_PATH, true);
            fileWriter.WriteLine(teamName);
            fileWriter.Close();
        }

        /// <summary>
        /// Retrieves all lines from a file.
        /// </summary>
        /// <param name="path">The path to the file to read.</param>
        /// <returns>A list containing each line from the file.</returns>
        private List<string> GetLinesFromFile(string path)
        {
            StreamReader fileReader = new StreamReader(path);
            List<string> lines = new List<string>();
            string currentLine = string.Empty;

            while ((currentLine = fileReader.ReadLine()) != null)
            {
                if (!string.IsNullOrEmpty(currentLine))
                {
                    lines.Add(currentLine);
                }
            }
            fileReader.Close();

            return lines;
        }

        /// <summary>
        /// Writes a list of lines to a specific file.
        /// </summary>
        /// <param name="path">The path of the file to write.</param>
        /// <param name="lines">The lines to be written.</param>
        private void WriteLinesToFile(string path, List<string> lines)
        {
            StreamWriter streamWriter = new StreamWriter(MANAGED_TEAMS_PATH, false);

            foreach (string currentLine in lines)
            {
                streamWriter.WriteLine(currentLine);
            }
            streamWriter.Close();
        }

        /// <summary>
        /// Writes one line of text to a file.
        /// </summary>
        /// <param name="path">The path to the file to be written.</param>
        /// <param name="line">The line to write.</param>
        private void WriteLineToFile(string path, string line)
        {
            StreamWriter streamWriter = new StreamWriter(path, false);
            streamWriter.WriteLine(line);
            streamWriter.Close();
        }

        /// <summary>
        /// Removes a team from the managed team list.
        /// </summary>
        /// <param name="teamName">The managed team to remove.</param>
        public void RemoveManagedTeam(string teamName)
        {
            List<string> currentManagedTeams = GetLinesFromFile(MANAGED_TEAMS_PATH);
            currentManagedTeams.Remove(teamName);

            WriteLinesToFile(MANAGED_TEAMS_PATH, currentManagedTeams);
        }

        /// <summary>
        /// Retrieves a list with all registered managed teams.
        /// </summary>
        public List<string> GetManagedTeams()
        {
            return GetLinesFromFile(MANAGED_TEAMS_PATH);
        }
    }
}
